package au.com.centrumsystems.hudson.plugin.buildpipeline;

import com.google.common.base.Function;
import com.google.common.collect.Lists;

import java.util.List;

public class GridForm<H extends HeaderForm, T extends CellForm<T>> {

    public static abstract class Builder<H extends HeaderForm, T extends CellForm<T>> {

        private Factory<H, T> factory;
        private H header;
        private List<ColumnForm.Builder<T>> columns;

        public Builder(Factory<H, T> factory) {
            this.factory = factory;
            this.columns = Lists.<ColumnForm.Builder<T>>newArrayList();
        }

        public Builder setHeader(H header) {
           this.header = header;
           return this;
        }

        public Builder setRoot(T cell) {
            return this.add(0, 0, cell);
        }

        private Builder add(int row, int column, T cell) {
            ColumnForm.Builder<T> builder = null;
            if (this.columns.size() > column) {
                builder = this.columns.get(column);
            } else {
                 builder = new ColumnForm.Builder<T>();
                 this.columns.add(column, builder);
            }
            builder.add(row, cell);

            column++;
            for (T dependency : cell.getDependencies()) {
                add(row, column, dependency);
                row += dependency.getMaxDependencies() + 1;
            }

            return this;
        }

        public GridForm<H, T> build() {
            return this.factory.create(
                header,
                Lists.transform(
                    this.columns,
                    new Function<ColumnForm.Builder<T>, ColumnForm<T>>() {
                        @Override
                        public ColumnForm<T> apply(ColumnForm.Builder<T> b) {
                            return b.build();
                        }
                    }));
        }
    }

    public interface Factory<H extends HeaderForm, T extends CellForm<T>> {
        GridForm<H, T> create(H header, List<ColumnForm<T>> columns);
    }

    private final H header;
    private final List<ColumnForm<T>> columns;
    private final String id;

    public GridForm(H header, List<ColumnForm<T>> columns, String id) {
        this.header = header;
        this.columns = columns;
        this.id = id;
    }

    public H getHeader() {
        return header;
    }

    public int getGridWidth() {
        return columns.size();
    }

    public int getGridHeight() {
        int height = 0;
        for (ColumnForm<T> column : columns) {
            height = Math.max(height, column.getHeight());
        }
        return height;
    }

    public T get(int x, int y) {
        return columns.get(y).get(x);
    }

    public boolean contains(int x, int y) {
        return columns.get(x).contains(y);
    }

    public String getId() {
        return id;
    }
}
